﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Xml;
using System.IO;

namespace PSE.Framework.ErrorLogging
{
    /// <summary>
    /// Informações do ambiente onde ocorreu o erro
    /// </summary>
    [Serializable]
    public class EnvironmentData
    {
        [XmlIgnore()]
        protected const string SEPARATOR = LogData.SEPARATOR;

        /// <summary>
        /// Sistema operacional
        /// </summary>
        [XmlAttribute]
        public string OperationalSystem { get; set; }
        /// <summary>
        /// Versão do sistema onde ocorreu o erro
        /// </summary>
        [XmlAttribute]
        public string SystemVersion { get; set; }

        /// <summary>
        /// Modelo do processador
        /// </summary>
        [XmlAttribute]
        public string ProcessorModel { get; set; }
        /// <summary>
        /// Uso do processador em porcentagem no momento do erro
        /// </summary>
        [XmlAttribute]
        public int ProcessorUsage { get; set; }

        /// <summary>
        /// Memória total do sistema em bytes
        /// </summary>
        [XmlAttribute]
        public long TotalPhysicalMemory { get; set; }
        /// <summary>
        /// Memória utilizada em bytes no momento do erro
        /// </summary>
        [XmlAttribute]
        public long TotalUsedPhysicalMemory { get; set; }
        /// <summary>
        /// Memória utilizada em bytes pelo processo no momento do erro
        /// </summary>
        [XmlAttribute]
        public long ProcessUsedPhysicalMemory { get; set; }

        /// <summary>
        /// Tamanho do disco rígido em bytes
        /// </summary>
        [XmlAttribute]
        public long HardDiskSize { get; set; }
        /// <summary>
        /// Espaço utilizado em bytes no disco rígido
        /// </summary>
        [XmlAttribute]
        public long UsedHardDiskSpace { get; set; }

        /// <summary>
        /// Nome da máquina
        /// </summary>
        [XmlAttribute]
        public string MachineName { get; set; }
        /// <summary>
        /// Domínio e nome do usuário
        /// </summary>
        [XmlAttribute]
        public string UserName { get; set; }
        /// <summary>
        /// Indica se o usuário é administrador local da máquina
        /// </summary>
        [XmlAttribute]
        public bool IsAdministrator { get; set; }

        /// <summary>
        /// Erros ocorridos na coleta das informações
        /// </summary>
        [XmlArray("Errors")]
        [XmlArrayItem("Error")]
        public List<string> Errors { get; set; }

        protected virtual string ToStringOverride()
        {
            return string.Empty;
        }

        public override string ToString()
        {
            StringBuilder logData = new StringBuilder();

            logData.AppendFormat("OperationalSystem:\t{0}", this.OperationalSystem);
            logData.AppendLine();
            logData.AppendFormat("SystemVersion:\t{0}", this.SystemVersion);
            logData.AppendLine();
            logData.AppendLine();

            logData.AppendFormat("ProcessorModel:\t{0}", this.ProcessorModel);
            logData.AppendLine();
            logData.AppendFormat("ProcessorUsage:\t{0}%", this.ProcessorUsage);
            logData.AppendLine();
            logData.AppendLine();

            logData.AppendFormat("TotalPhysicalMemory:\t{0:n0}", this.TotalPhysicalMemory);
            logData.AppendLine();
            logData.AppendFormat("TotalUsedPhysicalMemory:\t{0:n0}", this.TotalUsedPhysicalMemory);
            logData.AppendLine();
            logData.AppendFormat("ProcessUsedPhysicalMemory:\t{0:n0}", this.ProcessUsedPhysicalMemory);
            logData.AppendLine();
            logData.AppendLine();

            logData.AppendFormat("HardDiskSize:\t\t{0:n0}", this.HardDiskSize);
            logData.AppendLine();
            logData.AppendFormat("UsedHardDiskSpace:\t{0:n0}", this.UsedHardDiskSpace);
            logData.AppendLine();
            logData.AppendLine();

            logData.AppendFormat("MachineName:\t{0}", this.MachineName);
            logData.AppendLine();
            logData.AppendFormat("UserName:\t{0}", this.UserName);
            logData.AppendLine();
            logData.AppendFormat("IsAdministrator:\t{0}", Convert.ToString(this.IsAdministrator));
            logData.AppendLine();

            string extraFields = this.ToStringOverride();

            if (!string.IsNullOrEmpty(extraFields))
            {
                logData.AppendLine();
                logData.Append(extraFields);
            }

            if (this.Errors != null && this.Errors.Count > 0)
            {
                logData.AppendLine();
                logData.AppendLine("Environment Errors:");
                logData.AppendLine(SEPARATOR);
                logData.AppendLine(string.Join(Environment.NewLine + SEPARATOR + Environment.NewLine, this.Errors.ToArray()));
            }

            return logData.ToString();
        }

        public virtual void WriteTo(XmlWriter writer)
        {
            if (this.Errors != null && this.Errors.Count > 0)
            {
                writer.WriteElementString("Environment Errors", string.Join(Environment.NewLine + SEPARATOR + Environment.NewLine, this.Errors.ToArray()));
            }

            writer.WriteElementString("OperationalSystem", this.OperationalSystem);
            writer.WriteElementString("SystemVersion", this.SystemVersion);
            writer.WriteElementString("ProcessorModel", this.ProcessorModel);
            writer.WriteElementString("ProcessorUsage", string.Format("{0}%", this.ProcessorUsage));
            writer.WriteElementString("TotalPhysicalMemory", string.Format("{0:n0}", this.TotalPhysicalMemory));
            writer.WriteElementString("TotalUsedPhysicalMemory", string.Format("{0:n0}", this.TotalUsedPhysicalMemory));
            writer.WriteElementString("ProcessUsedPhysicalMemory", string.Format("{0:n0}", this.ProcessUsedPhysicalMemory));
            writer.WriteElementString("HardDiskSize", string.Format("{0:n0}", this.HardDiskSize));
            writer.WriteElementString("UsedHardDiskSpace", string.Format("{0:n0}", this.UsedHardDiskSpace));
            writer.WriteElementString("MachineName", this.MachineName);
            writer.WriteElementString("UserName", this.UserName);
            writer.WriteElementString("IsAdministrator", Convert.ToString(this.IsAdministrator));
        }
    }
}
